# _*_coding:utf-8_*_
from ATS.instrumentDriver.IVGeneralFunc import IVGeneralFunc_2410 as IVFunc
from ATS.util import mathlib as MathLib
import time
from ATS.datamanager.DataManager import DataManager

PIN_SMU = "SMU1"
INIT_MEASRNG = 0.001


def PIN_TEST(source, src_range, meas_range, compliance, meas_seq, common, spec, algorithm):
    """
    source = {"SMU1":([0,0=start,500=stop],1)}
    meas_range = {"SMU1":("Best Fixed", 0.01, 0)}
    source_range = {"SMU1": ("Best Fixed", 500=max(source),1)}
    compliance = {"SMU1": (0.001,0)}
    meas_seq = {"SMU1":(2,["V","I"])}
    common={"NPLC":1,"delay_time":0.1,"swp_pts":501}
    # FVMI
    src_val4GUI = [10,100,2]
    algorithm = 1
    src_range = {'SMU1': [u'Best Fixed', 100, 1]}
    compliance = {'SMU1': [0.1, 0]}
    source = {'SMU1': [[0, 10, 100], 1]}
    meas_seq = {'SMU1': [2, ['V', 'I']]}
    common = {'NPLC': 1, 'swp_pts': 2, 'delay_time': 0}
    spec = {'r_low': 0, 'i1_hi': 1, 'vbr_low': 0, 'v1': 400, 'vr': 100, 'r_hi': 1, 'vbr_hi': 1, 'i1_low': 0, 'ibr': 1}
    meas_range = {'SMU1': [u'Auto', 1e-06, 0]}
    """
    start = time.clock()
    mrng_FVMI_alg1 = []
    # print "start time", start
    smu_use = source.keys()[0]
    if PIN_SMU and len(source.keys()) == 1:
        k = smu_use
        update_k(source, k, PIN_SMU)
        update_k(meas_range, k, PIN_SMU)
        update_k(src_range, k, PIN_SMU)
        update_k(compliance, k, PIN_SMU)
        update_k(meas_seq, k, PIN_SMU)
        smu_use = PIN_SMU
    is_manual = DataManager().getgdata("Manual_Run")

    iv_flag = source[smu_use][1]
    if iv_flag == 0:
        meas_range[smu_use][-1] = 1

    src_mode = source[smu_use][0][0]
    if iv_flag == 0 and src_mode == 2:
        calc_i1 = False
    else:
        calc_i1 = True

    for k in meas_range:
        rng_mode = key_convert("rng_mode", meas_range[k][0])
        meas_range[k][0] = rng_mode
    for k in src_range:
        rng_mode = key_convert("rng_mode", src_range[k][0])
        src_range[k][0] = rng_mode

    DataManager().addgdata("IV_FLAG", iv_flag)
    DataManager().addgdata("CALC_I1", calc_i1)
    DataManager().addgdata("ALGORITHM", algorithm)
    # disable beeper
    if is_manual:
        # if 0:
        IVFunc.commonsetup(is_rst={smu_use: 1}, is_beep={smu_use: 0})
    else:
        IVFunc.commonsetup(is_beep={smu_use: 0})

    if algorithm == 1 and iv_flag == 1:
        raw_data = PIN_FVMI_alg1(source, src_range, meas_range, compliance, meas_seq, common, smu_use)
    else:
        raw_data = PIN_general(source, src_range, meas_range, compliance, meas_seq, common, smu_use, iv_flag)

    if is_manual:
        result = calc_judge(raw_data, spec)
        #        {'i': 0.01, 'ir': 0.02, 'r_low': 2, 'i1_hi': 0.01, 'vbr_low': 1, 'v1': 1, \
        #         'r_hi': 6, 'vbr_hi': 4, 'i1_low': -0.01}
        if iv_flag == 1:
            if algorithm == 0:
                k_out = ["V1", "I1_V1", "Ibr", "Vbr_Ibr", "Vr", "R_Vr", "I1_PorF", "Vbr_PorF", "R_PorF"]
            else:
                k_out = ["V1", "I1_V1", "Vr", "R_Vr", "I1_PorF", "R_PorF"]
        else:
            if algorithm == 0:
                k_out = ["V1", "I1_V1", "Ibr", "Vbr_Ibr", "Ir", "R_Ir", "I1_PorF", "Vbr_PorF", "R_PorF"]
            else:
                k_out = ["Ibr", "Vbr_Ibr", "Vbr_PorF"]
        for k in k_out:
            if k in result:
                __postdata(k, result[k])
    else:
        data_global = DataManager().getgdata("RAW_DATA")
        if data_global is None:
            data_global = {}
        data_global.update(raw_data)
        DataManager().addgdata("RAW_DATA", data_global)

    # print time.clock()-start
    return


def PIN_general(source, src_range, meas_range, compliance, meas_seq, common, smu_use, iv_flag):
    sweep = source
    step = {}
    bias = {}
    open = {}
    remote_sense = {}
    # Meas_Pro = {use_SMU:["V"]}
    meas_pro = {}
    common_ext = {"loop_mode": 1, "is_postdata": 0, "is_returndata": 1, "gs_flag": 1,
                  "avg_num": 1, "sample_pts": 1, "time_stamp": 0, "stop_comp": 0, "hold_time": 0,
                  "step_pts": 1, "off_0V": 1}
    common_ext.update(common)
    rval = IVFunc.setup(sweep, step, bias, open, meas_range, src_range, compliance, remote_sense,
                        meas_seq, meas_pro, common_ext)
    # print time.clock()-start
    if rval < 0:
        return reporterror("Reverse IV sweepping failed.", rval)
    rval = IVFunc.srcmeas(sweep, step, bias, open, meas_range, src_range, compliance, remote_sense,
                          meas_seq, meas_pro, common_ext)
    if iv_flag == 1:
        raw_data = {"V_FVMI": rval[smu_use]["V"], "I_FVMI": rval[smu_use]["I"]}
        raw_data["R_FVMI"] = [v / raw_data["I_FVMI"][ind] for ind, v in enumerate(raw_data["V_FVMI"])]
        __postdata("V", raw_data["V_FVMI"])
        __postdata("I", raw_data["I_FVMI"])
        __postdata("R", raw_data["R_FVMI"])
    else:
        raw_data = {"V_FIMV": rval[smu_use]["V"], "I_FIMV": rval[smu_use]["I"]}
        raw_data["R_FIMV"] = [v / raw_data["I_FIMV"][ind] for ind, v in enumerate(raw_data["V_FIMV"])]
        __postdata("V", raw_data["V_FIMV"])
        __postdata("I", raw_data["I_FIMV"])
        __postdata("R", raw_data["R_FIMV"])
    return raw_data


def PIN_FVMI_alg1(source, src_range, meas_range, compliance, meas_seq, common, smu_use):
    """
    algorithm = 1
    src_range = {'SMU1': [u'Best Fixed', 100, 1]}
    compliance = {'SMU1': [0.1, 0]}
    source = {'SMU1': [[0, 10, 100], 1]}
    meas_seq = {'SMU1': [2, ['V', 'I']]}
    common = {'NPLC': 1, 'swp_pts': 2, 'delay_time': 0}
    spec = {'r_low': 0, 'i1_hi': 1, 'vbr_low': 0, 'v1': 400, 'vr': 100, 'r_hi': 1, 'vbr_hi': 1, 'i1_low': 0, 'ibr': 1}
    meas_range = {'SMU1': [u'Auto', 1e-06, 0]}
    """
    sweep = {}
    step = {}
    bias = {}
    bias[smu_use] = [source[smu_use][0][1], source[smu_use][1]]
    open = {}
    remote_sense = {}
    meas_range_1 = {smu_use: [1, INIT_MEASRNG, 0]}
    # Meas_Pro = {use_SMU:["V"]}
    meas_pro = {}
    common_ext = {"loop_mode": 1, "is_postdata": 0, "is_returndata": 1, "gs_flag": 0,
                  "avg_num": 1, "sample_pts": 1, "time_stamp": 0, "stop_comp": 0, "hold_time": 0,
                  "step_pts": 1, "off_0V": 1}
    common_ext.update(common)
    rval = IVFunc.setup(sweep, step, bias, open, meas_range_1, src_range, compliance, remote_sense,
                        meas_seq, meas_pro, common_ext)
    # print time.clock()-start
    if rval < 0:
        return reporterror("Reverse IV sweepping failed.", rval)
    rval = IVFunc.srcmeas(sweep, step, bias, open, meas_range_1, src_range, compliance, remote_sense,
                          meas_seq, meas_pro, common_ext)
    raw_data = {"V_FVMI": rval[smu_use]["V"], "I_FVMI": rval[smu_use]["I"]}
    bias[smu_use][0] = source[smu_use][0][2]
    meas_range_2 = meas_range
    rval = IVFunc.setup(sweep, step, bias, open, meas_range_2, src_range, compliance, remote_sense,
                        meas_seq, meas_pro, common_ext)
    # print time.clock()-start
    rval = IVFunc.srcmeas(sweep, step, bias, open, meas_range_2, src_range, compliance, remote_sense,
                          meas_seq, meas_pro, common_ext)
    raw_data["V_FVMI"].append(rval[smu_use]["V"][0])
    raw_data["I_FVMI"].append(rval[smu_use]["I"][0])
    raw_data["R_FVMI"] = [v / raw_data["I_FVMI"][ind] for ind, v in enumerate(raw_data["V_FVMI"])]
    __postdata("V", raw_data["V_FVMI"])
    __postdata("I", raw_data["I_FVMI"])
    __postdata("R", raw_data["R_FVMI"])

    return raw_data


def reporterror(msg, err_code):
    # print "********* reporterror",msg
    DataManager().posterror(msg)
    return err_code


def __postdata(name, val):
    # print name, val
    if isinstance(val, type([])):
        DataManager().postarraydata(name, val)
    else:
        DataManager().postSingleData(name, val)


#    print "########",name, val
def update_k(org, old_k, new_k):
    if new_k not in org:
        org[new_k] = org[old_k]
        del org[old_k]
    return org


def key_convert(type_code, words):
    if type_code == "rng_mode":
        if words == "Limited Auto":
            return 2
        elif words == "Fixed":
            return 1
        elif words == "Auto":
            return 0
        elif words == "Best Fixed":
            return 1


def calc_judge_alg0(raw_data, spec, result):
    iv_flag = DataManager().getgdata("IV_FLAG")
    calc_i1 = DataManager().getgdata("CALC_I1")
    # print raw_data, spec
    if iv_flag == 1:
        v_val = raw_data["V_FVMI"]
        i_val = raw_data["I_FVMI"]
        r_val = raw_data["R_FVMI"]
    else:
        v_val = raw_data["V_FIMV"]
        i_val = raw_data["I_FIMV"]
        r_val = raw_data["R_FIMV"]
    if spec.get("v1") is not None and spec.get("i1_hi") is not None and spec.get("i1_low") is not None and calc_i1:
        pos_V1 = MathLib.FINDLIN(v_val, spec["v1"], 0)
        result["I1_V1"] = MathLib.AT(i_val, pos_V1)
        result["V1"] = spec["v1"]
        if result["I1_V1"] > spec["i1_hi"] or result["I1_V1"] < spec["i1_low"]:
            result["I1_PorF"] = 0
    else:
        result.pop("I1_PorF")
    if spec.get("ibr") is not None and spec.get("vbr_hi") is not None and spec.get("vbr_low") is not None:
        max_i_val = max(MathLib.ABS(i_val))
        if abs(spec["ibr"]) >= max_i_val:
            result["Vbr_Ibr"] = v_val[-1]
        else:
            pos_Ibr = MathLib.FINDLIN(i_val, spec["ibr"], 0)
            result["Vbr_Ibr"] = MathLib.AT(v_val, pos_Ibr)
        result["Ibr"] = spec["ibr"]
        if result["Vbr_Ibr"] > spec["vbr_hi"] or result["Vbr_Ibr"] < spec["vbr_low"]:
            result["Vbr_PorF"] = 0
    else:
        result.pop("Vbr_PorF")
    if iv_flag == 1:
        if spec.get("vr") is not None and spec.get("r_hi") is not None and spec.get("r_low") is not None:
            pos_Vr = MathLib.FINDLIN(v_val, spec["vr"], 0)
            result["R_Vr"] = MathLib.AT(r_val, pos_Vr)
            result["Vr"] = spec["vr"]
            if result["R_Vr"] > spec["r_hi"] or result["R_Vr"] < spec["r_low"]:
                result["R_PorF"] = 0
        else:
            result.pop("R_PorF")
    else:
        if spec.get("ir") is not None and spec.get("r_hi") is not None and spec.get("r_low") is not None:
            pos_Ir = MathLib.FINDLIN(i_val, spec["ir"], 0)
            result["R_Ir"] = MathLib.AT(r_val, pos_Ir)
            result["Ir"] = spec["ir"]
            if result["R_Ir"] > spec["r_hi"] or result["R_Ir"] < spec["r_low"]:
                result["R_PorF"] = 0
        else:
            result.pop("R_PorF")


def calc_judge_alg1(raw_data, spec, result):
    # error check
    if "V_FVMI" not in raw_data:
        result["R_Vr"] = -9999
        result["Vr"] = -9999
        result["I1_V1"] = -9999
        result["V1"] = -9999
        result["R_PorF"] = 0
        result["I1_PorF"] = 0
    else:
        result["R_Vr"] = raw_data["R_FVMI"][0]
        result["Vr"] = raw_data["V_FVMI"][0]
        if result["R_Vr"] > spec["r_hi"] or result["R_Vr"] < spec["r_low"]:
            result["R_PorF"] = 0
        result["I1_V1"] = raw_data["I_FVMI"][1]
        result["V1"] = raw_data["V_FVMI"][1]
        if result["I1_V1"] > spec["i1_hi"] or result["I1_V1"] < spec["i1_low"]:
            result["I1_PorF"] = 0
    if "V_FIMV" not in raw_data:
        result["Vbr_Ibr"] = -9999
        result["Ibr"] = -9999
        result["Vbr_PorF"] = 0
    else:
        result["Vbr_Ibr"] = raw_data["V_FIMV"][1]
        result["Ibr"] = raw_data["I_FIMV"][1]
        if result["Vbr_Ibr"] > spec["vbr_hi"] or result["Vbr_Ibr"] < spec["vbr_low"]:
            result["Vbr_PorF"] = 0


def calc_judge(raw_data, spec):
    """
    raw_data = {"V_FVMI":[],"I_FVMI":[],"R_FVMI":[],"V_FIMV":[],"I_FIMV":[], "R_FIMV":[]}
    spec = {"V1":400,"Ibr":0.0001, "Vr":166, "I1_Hi":0.001, "I1_Low":0,"Vbr_Hi":0.001,"Vbr_Low":0,\
            "R_Hi":150, "R_Low":100}
    spec = {"V1":400, "I1_Hi":0.001, "I1_Low":-0.001, "Ibr":0.002, "Vbr_Hi":60,  "Vbr_Low":0,\
            "Ir":0.003, "R_Hi":20,"R_Low":10}
    {'ibr': 0.01, 'ir': 0.02, 'r_low': 2, 'i1_hi': 0.01, 'vbr_low': 1, 'v1': 1, 'r_hi': 6,\
             'vbr_hi': 4, 'i1_low': -0.01}
    """
    algorithm = DataManager().getgdata("ALGORITHM")
    result = {"I1_PorF": 1, "Vbr_PorF": 1, "R_PorF": 1}

    if algorithm == 0:
        calc_judge_alg0(raw_data, spec, result)
    else:
        calc_judge_alg1(raw_data, spec, result)
    return result


def siteend_calc():
    # print "********* in siteend_calc"
    err_code = -1001
    cur_site = DataManager().getgdata("siteID")
    iv_flag = DataManager().getgdata("IV_FLAG")
    algorithm = DataManager().getgdata("ALGORITHM")
    cur_site = cur_site.lower()
    proj_setting = DataManager().getCurIni()
    crit = proj_setting["CRITERIA"]
    limit_k = None
    for k in crit:
        sites = crit[k].split(",")
        sites = [s.strip().lower() for s in sites]
        if cur_site in sites:
            limit_k = k
    if limit_k is None or limit_k.upper() not in proj_setting:
        msg = "Cannot find out spec value (%s) for current site %s." % (limit_k.upper(), cur_site)
        reporterror(msg, err_code)
        return
    limit_k = limit_k.upper()
    raw_data = DataManager().getgdata("RAW_DATA")
    spec = proj_setting[limit_k]
    for k in spec:
        spec[k] = eval(spec[k])
    result = calc_judge(raw_data, spec)
    k_out = ["V1", "I1_V1", "Ibr", "Vbr_Ibr", "Ir", "Vr", "R_Vr", "R_Ir", "I1_PorF", "Vbr_PorF", "R_PorF"]
    for k in k_out:
        if k in result:
            __postdata(k, result[k])


if __name__ == "__main__":
    import InstCom

    InstCom.getinstconfig("online.rcf")
    # print InstCom.inst_dict
    """
    use_SMU = "SMU1"
    vbr_crit = -31 #judge
    Id4neg_crit = 0.1 #judge
    atId = -0.01  # if alg4neg=0, atId = ''
    atVr = -5    # if alg4neg=0, atId = ''
    src_mode = 'Linear Sweep'
    src_val = (0,-35,101)
    src_rng = 'Best Fixed'
    src_delay = 0
    measI_rng = 'Limited Auto'
    measI_rng_val = 1e-6
    limitI = 0.02
    nPLC = 0.1
    RF_crit = 50 #judge
    alg4pos = 1
    alg4neg = 1 #use algrithm 2
    VF = '' #@VF,not use it if alg4pos=0,use algrithm 1
    src_mode4pos = 'Linear Sweep'
    src_val4pos = (0,2,51)
    #src_val4pos = 0.85
    srcv_rng4pos = 'Best Fixed'
    src_delay4pos = 0
    measI_rng4pos = 'Limited Auto'
    measI_rng_val4pos = 1e-6
    limitI4pos = 0.1
    nPLC4pos = 0.1
    start=time.clock()
    PIN_TEST(vbr_crit,Id4neg_crit,atId,atVr,src_mode,src_val,src_rng,src_delay,measI_rng,measI_rng_val,limitI,nPLC,RF_crit,alg4pos,alg4neg,VF,src_mode4pos,src_val4pos,srcv_rng4pos,src_delay4pos,measI_rng4pos,measI_rng_val4pos,limitI4pos,nPLC4pos)
    """

#    source = {"SMU1":([0,0,500],1)}
#    meas_range = {"SMU1":("Best Fixed", 0.01, 0)}
#    source_range = {"SMU1": ("Best Fixed", 500,1)}
#    compliance = {"SMU1": (0.001,0)}
#    meas_seq = {"SMU1":(2,["V","I"])}
#    common={"NPLC":1,"delay_time":0.1,"swp_pts":501}
#    spec={"R_Lo":0.1,"R_Hi":10}
#    PIN_TEST(source,meas_range,source_range, compliance,meas_seq, common, spec)

#    print "Elapsed time",time.clock()-start
